<?php
namespace phpcodehub\files;
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/6/15 0015
 * Time: 下午 3:05
 */
class FileUpload
{
    private $path = 'data';                                  //upload file save directory
    private $allowtype = ['jpg','gif','png'];       //allow uploading file's type
    private $maxsize =  6 * 1024 * 1024;             //allow uploading file's maxsize (bytes)
    private $israndname = true;

    private $originName;
    private $tmpFileName;
    private $fileType;
    private $fileSize;
    private $newFIleName;
    private $errorCode = 0;
    private $errorMessage;

    public function set( $key, $value ){
        $key = strtolower( $key );

        if ( array_key_exists( $key, get_class_vars( get_class( $this ) ) ) ) {
            $this->setOption( $key, $value );
        }

        return $this;
    }

    /*
     * @parme string $fileField   the form table name of the file
     * @return bool               success:true    failed:false
     */
    public function upload( $fileField ) {
        if ( !$this->checkFilePath() ) {
            $this->errorMessage = $this->getError();
            return false;
        }

        $file = $_FILES[ $fileField ];
        $name = $file['name'];
        $tmp_name = $file['tmp_name'];
        $size = $file['size'];
        $error = $file['error'];

        if ( is_array( $name ) ) {
            return $this->multipleUpload( $name, $tmp_name, $size, $error ) ? true : false;
        }
        else {
            return $this->singleUpload( $name, $tmp_name, $size, $error ) ? true : false;
        }
    }

    private function multipleUpload( $name, $tmp_name, $size, $error ) {
        $return = true;
        $errors = array();

        for ( $i = 0; $i < count( $name ); $i++ ) {
            if ( $this->setFiles( $name[$i], $tmp_name[$i], $size[$i], $error[$i] ) ) {
                if ( !$this->checkFIleType() || !$this->checkFileSize() ) {
                    $errors[] = $this->getError();
                    $return = false;
                }
            }
            else {
                $errors[] = $this->getError();
                $return = false;
            }

            if ( !$return ) {
                $this->setFiles();
            }
        }
        if ( $return ) {
            $fileNames = array();

            for ( $i = 0; $i < count( $name ); $i++ ) {
                if ( $this->setFiles( $name[$i], $tmp_name[$i], $size[$i], $error[$i] ) ) {
                    $this->setNewFileName();
                    if ( !$this->copyFile() ) {
                        $errors[] = $this->getError();
                        $return = false;
                    }
                    $fileNames[] = $this->newFIleName;
                }
            }
            $this->newFIleName = $fileNames;
        }
        $this->errorMessage = $errors;
        return $return;
    }

    private function singleUpload( $name, $tmp_name, $size, $error ) {
        if ( $this->setFiles( $name, $tmp_name, $size, $error ) ) {
            if ( $this->checkFIleType() && $this->checkFileSize() ) {
                $this->setNewFileName();
                if ( $this->copyFile() ) {
                    return true;
                }
                else {
                    $return = false;
                }
            }
            else {
                $return = false;
            }
        }
        else {
            $return = false;
        }

        if ( !$return ) {
            $this->errorMessage = $this->getError();
        }
        return $return;
    }

    private function setFiles( $name = '', $tmp_name = '', $size = 0, $error = 0 ) {
        $this->errorCode = $error;

        if ( $error ) {
            return false;
        }

        $this->originName = $name;
        $this->tmpFileName = $tmp_name;
        $aryStr = explode( '.', $name );
        $this->fileType = strtolower( $aryStr[ count( $aryStr ) - 1 ] );
        $this->fileSize = $size;
        return true;
    }

    public function getErrorMessage() {
        return $this->errorMessage;
    }

    private function setOption( $key, $value ){
        $this->$key = $value;
    }

    private function checkFilePath() {
        if ( empty( $this->path ) ) {
            $this->errorCode = -5;
            return false;
        }

        if ( !file_exists( $this->path ) || !is_writable( $this->path ) ) {
            if ( !@mkdir( $this->path, 0755 ) ) {
                $this->errorCode = -4;
                return false;
            }
        }
        return true;
    }

    private function checkFileSize() {
        if ( $this->fileSize > $this->maxsize ) {
            $this->errorCode = -2;
            return false;
        }
        else {
            return true;
        }
    }

    private function checkFIleType() {
        if ( in_array( $this->fileType, $this->allowtype ) ) {
            return true;
        }
        else {
            $this -> errorCode = -1;
            return false;
        }
    }

    private function setNewFileName() {
        if ( $this->israndname ) {
            $this->newFIleName = $this->proRandName();
        }
        else {
            $this->newFIleName = $this->originName;
        }
    }

    private function proRandName() {
        $fileName = date('YmdHis') . '_' . rand(100,999);
        return $fileName . '.' . $this->fileType;
    }

    private function getError() {
        $str = '上传文件时出错：';

        switch ( $this->errorCode ) {
            case 4:
                $str .= '没有文件被上传';
                break;
            case 3:
                $str .= '文件只有部分被上传';
                break;
            case 2:
                $str .= '上传文件的大小超过了HTML表单中MAX_FILE_SIZE选项值';
                break;
            case 1:
                $str .= '上传文件的大小超过了php.ini中upload_maxfilesize配置值';
                break;
            case -1:
                $str .= '未被允许上传的文件类型';
                break;
            case -2:
                $str .= '上传文件过大，超过了'.$this->maxsize.'bytes的限制';
                break;
            case -3:
                $str .= '上传失败';
                break;
            case -4:
                $str .= '建立文件存放目录失败，请重新指定目录';
                break;
            case -5:
                $str .= '必须指定文件存在的路径';
                break;
            default:
                $str .= '未知错误';
                break;
        }
        return $str;
    }

    private function copyFile() {
        if ( !$this->errorCode ) {
            $path = rtrim( $this->path, '/') . '/';
            $path .= $this->newFIleName;
            if ( @move_uploaded_file( $this->tmpFileName, $path )) {
                return true;
            }
            else {
                $this->errorCode = -3;
                return false;
            }
        }
        else {
            return false;
        }
    }
}